import os
import re
import sys
from os.path import abspath
import json

root_path = "/"
self_subsystem_name = "common"
self_part_name = "common"

system_library_info = {
    "openssl":{
      "libssl_openssl":"libssl",
      "libcrypto_openssl":"libcrypto"
    },
    "zlib": {
      "libz":"libz"
    }
}

soname_transfer = {
    "libcrypto_openssl":"libcrypto_shared",
    "libssl_openssl":"libssl_shared",
    "libz":"libz"
}



Copyright = """# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""

gn_header = """import("//build/templates/metadata/module_info.gni")
import("//build/config/python.gni")
import("//build/config/clang/clang.gni")

"""

gn_template = """template("build_thirdparty") {
    if (invoker.type == "shared") {
        _main_target_name = target_name
        _target_label = get_label_info(":${_main_target_name}", "label_with_toolchain")
        _subsystem_name = invoker.subsystem_name
        _part_name = invoker.part_name    
    }

    _deps = []
    if(defined(invoker.deps)) {
        _deps += invoker.deps
    }
    action(target_name) {
        forward_variables_from(invoker,
                                 [
                                   "sources",
                                   "outputs",
                                   "args",
                                   "script",
                                 ])
        deps = _deps
        if (invoker.type == "shared") {
            _install_module_info = {
              module_def = _target_label
              module_info_file =
                  rebase_path(get_label_info(_target_label, "target_out_dir"),
                              root_build_dir) +
                  "/${_main_target_name}_module_info.json"
              subsystem_name = _subsystem_name
              part_name = _part_name
              toolchain = current_toolchain
              toolchain_out_dir = rebase_path(root_out_dir, root_build_dir)
            }

            metadata = {
              install_modules = [ _install_module_info ]
            }
        }            
    }
    if (invoker.type == "shared") {
        generate_module_info("${_main_target_name}_info") {
            module_name = _main_target_name
            module_type = "lib"
            module_source_dir = "${target_out_dir}"
            install_enable = true
            module_install_images = [ "system" ]
        }   
    }        
}

"""

gn_config = """config("@todo_lib_name_config") {
    if (!defined(ldflags)) {
        ldflags = []
    }
    if (!defined(libs)) {
        libs = []
    }
    ldflags += [ "-L@todo_subsystem_name/@todo_part_name" ]
    libs += [ "@todo_lib_name" ]
}

"""

gn_build = """build_thirdparty("@todo_thirdparty_lib_name") {
    type = @todo_libtype
    script = "build_thirdparty.sh"
    sources = [ "//third_party/@todo_thirdparty_name" ]
    outputs = [ "${target_out_dir}/@todo_thirdparty_lib_name" ]
    args = [
        rebase_path(target_out_dir,root_build_dir),
        rebase_path(root_build_dir,"//third_party/@todo_thirdparty_name")
    ]
    if (type == "shared") {
        subsystem_name = "@todo_subsystem_name"
        part_name = "@todo_part_name"    
    }
    deps = [
        @todo_thirdparty_deps
    ]
}

"""

gn_group = """group("@todo_thirdparty_name") {
    deps = [
        @todo_thirdparty_deps
    ]
}

"""

sh_default = """#!/bin/sh

root_dir=`pwd`
outputDir=$root_dir/@todo_subsystem_name/@todo_part_name
mkdir -p $outputDir
flag="-DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DLIBRARY_OUTPUT_PATH=$outputDir -DEXECUTABLE_OUTPUT_PATH=$outputDir -DCMAKE_INSTALL_PREFIX=$outputDir @todo_define .."
@todo_deps
cd @todo_path
mkdir thirdparty_build
cd thirdparty_build
cmake $flag
make -j8
make install

if [ -e "lib" ];then
    cp lib/* $outputDir -rfa
fi

if [ -e "bin" ];then
    cp bin/* $outputDir -rfa
fi

cd - && cd $outputDir

if [ -e "lib" ];then
    cp lib/* $outputDir -rfa
fi


cd -

if [ "`ls $outputDir/lib*.so*`" != "" ];then
    mkdir -p $2/$1
    cp $outputDir/lib*.so* $2/$1 -rfa
fi


"""

cmake_cflag_arm64 = """set(CMAKE_C_FLAGS "--sysroot=${OHOS_SYSROOT} -Xclang -mllvm -Xclang -instcombine-lower-dbg-declare=0 --target=aarch64-linux-ohos -D__MUSL__ @todo_flag")"""

cmake_cxxflag_arm64 = """set(CMAKE_CXX_FLAGS "--sysroot=${OHOS_SYSROOT} -fvisibility-inlines-hidden -Xclang -mllvm -Xclang -instcombine-lower-dbg-declare=0 --target=aarch64-linux-ohos -D__MUSL__ @todo_flag")"""

cmake_cflag_arm = """set(CMAKE_C_FLAGS "--sysroot=${OHOS_SYSROOT} -Xclang -mllvm -Xclang -instcombine-lower-dbg-declare=0 --target=arm-linux-ohosmusl -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -mfpu=neon -D__MUSL__ @todo_flag")"""

cmake_cxxflag_arm = """set(CMAKE_CXX_FLAGS "--sysroot=${OHOS_SYSROOT} -fvisibility-inlines-hidden -Xclang -mllvm -Xclang -instcombine-lower-dbg-declare=0 --target=arm-linux-ohosmusl -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -mfpu=neon -D__MUSL__ @todo_flag")"""

cmake_toolchain_default = """set(CMAKE_CROSSCOMPILING TRUE)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR @todo_cpu)
set(OHOS_SRC_HOME @todo_path)
set(OHOS_ROOT_BUILD_DIR ${OHOS_SRC_HOME}/out/@todo_platform)
set(OHOS_TOOLCHAIN ${OHOS_SRC_HOME}/prebuilts/clang/ohos/linux-x86_64/llvm/bin)
set(OHOS_SYSROOT ${OHOS_ROOT_BUILD_DIR}/obj/third_party/musl)
set(CMAKE_C_COMPILER ${OHOS_TOOLCHAIN}/clang)
set(CMAKE_CXX_COMPILER ${OHOS_TOOLCHAIN}/clang++)
@todo_cflag
@todo_cxxflag
set(MY_LINK_FLAGS "--target=arm-linux-ohosmusl --sysroot=${OHOS_SYSROOT}")
set(CMAKE_CXX_LINKER ${OHOS_TOOLCHAIN}/clang++)
set(CMAKE_C_LINKER ${OHOS_TOOLCHAIN}/clang)
set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINKER} ${MY_LINK_FLAGS} <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINKER} ${MY_LINK_FLAGS} <FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
"""

bundle = """{
    "name": "",
    "description": "",
    "version": "",
    "license": "",
    "publishAs": "",
    "segment": {
    },
    "dirs": {},
    "scripts": {},
    "licensePath": "",
    "readmePath": {
    },
    "component": {
        "name": "@todo_part_name",
        "subsystem": "@todo_subsystem_name",
        "syscap": [],
        "features": [],
        "adapted_system_type": [],
        "rom": "",
        "ram": "",
        "deps": {
            "components": [],
            "third_party": []
        },
        "build": {
            "sub_component": [
                "//third_party/@todo_thirdparty_name:@todo_thirdparty_name"
            ],
            "inner_kits": [],
            "test": [
            ]
        }
    }
}
"""

def generate_bundle(config):
    thirdparty_name = config[0]
    fileName = os.path.join(root_path, "bundle.json")
    fd = open(fileName, "w")
    writeStr = bundle.replace("@todo_thirdparty_name", thirdparty_name)
    writeStr = writeStr.replace("@todo_part_name", self_part_name)
    writeStr = writeStr.replace("@todo_subsystem_name", self_subsystem_name)
    fd.write(writeStr)
    fd.close()

def get_include(file_txt,index,lst,path):
    if file_txt.find("include_dirs",index) != -1:
        index = file_txt.find("include_dirs",index) + 1
        end = file_txt.find("]",index)
        ohos_dir = abspath(root_path + "/../..")
        while True:
            if file_txt[index] == "]":
                break
            contentStart = file_txt.find("\"",index)+1
            contentEnd = file_txt.find("\"",contentStart+1)
            if contentEnd > end:
                break
            index = contentEnd + 1
            tmp = file_txt[contentStart:contentEnd]
            if tmp != "":
                if tmp.find("//third_party") != -1:
                   tmp = tmp.replace("//third_party","../")
                   tmp = abspath(tmp)
                else:
                    tmp = os.path.dirname(path) + "/" + tmp
                    tmp = abspath(tmp)
                if tmp not in lst:
                    lst.append(tmp)
        get_include(file_txt, end+1, lst, path)
    
def generate_toolchain(config):
    ohos_dir = abspath(root_path + "/../..")
    platform = config[4]
    cpu = config[5]
    todo_flag = config[7]
    depends = config[8]
    fileName = os.path.join(root_path, "toolchain.cmake")
    fd = open(fileName, "w")
    writeStr = cmake_toolchain_default.replace("@todo_path", ohos_dir)
    writeStr = writeStr.replace("@todo_platform", platform)
    if (cpu == "arm"):
        writeStr = writeStr.replace("@todo_cflag", cmake_cflag_arm.replace("@todo_flag", todo_flag))
        writeStr = writeStr.replace("@todo_cxxflag", cmake_cxxflag_arm.replace("@todo_flag", todo_flag))
        writeStr = writeStr.replace("@todo_cpu", "arm")
    elif (cpu == "arm64"):
        writeStr = writeStr.replace("@todo_cflag", cmake_cflag_arm64.replace("@todo_flag", todo_flag))
        writeStr = writeStr.replace("@todo_cxxflag", cmake_cxxflag_arm64.replace("@todo_flag", todo_flag))
        writeStr = writeStr.replace("@todo_cpu", "aarch64")
    fd.write(writeStr)
    fd.write("list(APPEND CMAKE_PREFIX_PATH \"${OHOS_ROOT_BUILD_DIR}/obj/third_party/musl/usr/include/aarch64-linux-ohos\")\n")
    fd.write("list(APPEND CMAKE_PREFIX_PATH \"${OHOS_ROOT_BUILD_DIR}/obj/third_party/musl/usr/lib/aarch64-linux-ohos\")\n")
    fd.write("list(APPEND CMAKE_PREFIX_PATH \"${OHOS_ROOT_BUILD_DIR}/obj/third_party/musl/usr/include/arm-linux-ohos\")\n")
    fd.write("list(APPEND CMAKE_PREFIX_PATH \"${OHOS_ROOT_BUILD_DIR}/obj/third_party/musl/usr/lib/arm-linux-ohos\")\n")
    
    if (len(depends) <= 0):
        fd.close()
        return
    lst = []
    for i in depends:
        lib = i["thirdparty_name"]
        if lib == "":
            continue
        subsystemName = "common"
        partName = "common"
        if i["subsystem_name"] != "":
            subsystemName = i["subsystem_name"]
        if i["subsystem_name"] != "":
            partName = i["party_name"]            
        fd.write("list(APPEND CMAKE_PREFIX_PATH \"${OHOS_ROOT_BUILD_DIR}/obj/third_party/" + lib + "\")" + "\n")
        fd.write("list(APPEND CMAKE_PREFIX_PATH \"${OHOS_ROOT_BUILD_DIR}/" + subsystemName + "/" + partName + "\")" + "\n")
        fd.write("include_directories(\"${OHOS_ROOT_BUILD_DIR}" + subsystemName + "/" + partName + "/include\")\n")
        
        val = os.popen("find " + ohos_dir + "/third_party/" + lib + "|grep BUILD.gn$")
        for path in val.readlines():
            file_fd = open(path.strip(),'r')
            file_txt = file_fd.read()
            get_include(file_txt,0,lst,path)
            file_fd.close()
    for everyPath in lst:
        fd.write("include_directories(\"" + everyPath + "\")\n")   
    fd.close()
    
    
def generate_sh(config):
    defines = config[6]
    platform = config[4]
    ohos_dir = abspath(root_path + "/../..")
    outputDir = ohos_dir + "/out/" + platform 
    fileName = os.path.join(root_path, "build_thirdparty.sh")
    fd = open(fileName, 'w')
    writeStr = sh_default.replace("@todo_subsystem_name", self_subsystem_name)
    writeStr = writeStr.replace("@todo_part_name", self_part_name)
    writeStr = writeStr.replace("@todo_define", defines)
    writeStr = writeStr.replace("@todo_path", root_path) 
    thirdpartyLib = config[1]
    todo_deps = ""   

    deps = config[8]
    if (len(deps) > 0):
        for i in deps:
            libName = i["thirdparty_name"]
            libPath = outputDir + "/" + i["subsystem_name"] + "/" + i["party_name"]
            try:
                if system_library_info[libName] != "":
                    for j in system_library_info[libName]:
                        todo_deps += "if [ -e \"" + libPath + "/" + j + ".z.so\" ];then\n    "
                        todo_deps += "rm " + libPath + "/" +system_library_info[libName][j] + ".so\n    "
                        todo_deps += "ln -s " + libPath + "/" + j + ".z.so " + libPath + "/" +system_library_info[libName][j] + ".so\n"
                        todo_deps += "fi\n\n"
            except:
                todo_deps += ""
    writeStr = writeStr.replace("@todo_deps", todo_deps)    
    fd.write(writeStr)
    fd.close()
    os.chmod(fileName, 0o777)

def write_gn_group(fd, thirdpartyName, deps):
    writeStr = gn_group.replace("@todo_thirdparty_name", thirdpartyName)
    writeStr = writeStr.replace("@todo_thirdparty_deps", deps)
    fd.write(writeStr)


def write_gn_build(fd, libName, libType, config):
    thirdpartyName = config[0]
    allDeps = ""
    writeStr = gn_build.replace("@todo_thirdparty_lib_name", libName)
    writeStr = writeStr.replace("@todo_libtype", libType)
    writeStr = writeStr.replace("@todo_thirdparty_name", thirdpartyName)
    writeStr = writeStr.replace("@todo_subsystem_name", self_subsystem_name)
    writeStr = writeStr.replace("@todo_part_name", self_part_name)
    deps = config[8]
    if (len(deps) <= 0):
        writeStr = writeStr.replace("@todo_thirdparty_deps", "")
    else:
        for i in deps:
            lib = i["thirdparty_name"]
            if lib == "":
                continue
            try:
                for key in system_library_info[lib]:
                    if soname_transfer[key] != "" :
                        key = soname_transfer[key]
                        tmpstr = "\"//third_party/" + lib + ":" + key + "\",\n        "
                        if tmpstr not in allDeps:
                            allDeps += tmpstr
            except:
                tmpstr = "\"//third_party/" + lib + ":" + lib + "\",\n        "
                if tmpstr not in allDeps:
                    allDeps += tmpstr
                
    writeStr = writeStr.replace("@todo_thirdparty_deps", allDeps)
    fd.write(writeStr)
    
def write_gn_config(fd, libName):
    if libName == "":
        return
    libName = re.sub(r"lib", "", libName, count = 1)
    libName = re.sub(r"\.so.*", "", libName, count = 0)
    libName = re.sub(r"\.a.*", "", libName, count = 0)
    writeStr = gn_config.replace("@todo_lib_name", libName)
    writeStr = writeStr.replace("@todo_subsystem_name", self_subsystem_name)
    writeStr = writeStr.replace("@todo_part_name", self_part_name)
    fd.write(writeStr)

def generate_gn(config):
    groupDepsStr = ""
    fileName = os.path.join(root_path, "BUILD.gn")
    gnPath = abspath(root_path + "/../../prebuilts/build-tools/linux-x86/bin/gn")
    fd = open(fileName, 'w')
    fd.write(Copyright)
    fd.write(gn_header)
    fd.write(gn_template)
    libData = config[1]
    static_lib = libData[0]["static"]
    shared_lib = libData[1]["shared"]
    for libname in static_lib:
        write_gn_config(fd, libname)
    for libname in shared_lib:
        write_gn_config(fd, libname)
    if (len(shared_lib) == 0):
        write_gn_build(fd, static_lib[0], "\"static\"", config)
        groupDepsStr += "\":" + static_lib[0] + "\",\n        "
    else:
        for i in shared_lib:
            write_gn_build(fd, i, "\"shared\"", config)
            groupDepsStr += "\":" + i + "\",\n        "
    write_gn_group(fd, config[0], groupDepsStr)
    fd.close()
    os.system(gnPath + " format " + fileName + " >> /dev/null")

def delete_version(arg):
    for root, dirs, files in os.walk(arg):
        for file in files:
            if file == "CMakeLists.txt":
                flag = 0
                filePath = root + "/" + file
                with open(filePath.strip(), 'r', encoding="utf-8") as file_fd:
                    file_txt = file_fd.read()
                    index = 0
                    while True:
                        if file_txt.find("set_target_properties",index) != -1:
                            start = file_txt.find("set_target_properties",index)
                            end = file_txt.find(")",start)
                            index = end + 1
                            str1 = file_txt[start:end+1]
                            if str1.find("VERSION") != -1:
                                file_txt = file_txt.replace(str1,"")
                                index = start + 1
                                flag = 1
                        else :
                            break
                    file_fd.close()
                    if flag == 1:
                        with open(filePath.strip(), 'w', encoding="utf-8") as file_fd:
                            file_fd.write(file_txt)
                            file_fd.close()

def init(fileName,config):
    f = open(fileName, encoding="utf-8")
    jsonData = json.load(f)
    config[0] = jsonData["thirdparty_name"]
    config[1] = jsonData["thirdparty_lib"]
    if (jsonData["subsystem_name"] != ""):
        config[2] = jsonData["subsystem_name"]
        global self_subsystem_name
        self_subsystem_name = config[2]
    if (jsonData["part_name"] != ""):
        config[3] = jsonData["part_name"]
        global self_part_name
        self_part_name = config[3]
    if (jsonData["platform"] != ""):
        config[4] = jsonData["platform"]
    if (jsonData["cpu"] != ""):
        config[5] = jsonData["cpu"]
    config[6] = jsonData["defines"]
    config[7] = jsonData["additional_compile_flag"]
    config[8] = jsonData["depends"]
    return config

def start(path):
    config = ["", "", "common", "common", "rk3568", "arm", "", "", ""]
    global root_path
    root_path = abspath(path)
    delete_version(root_path)
    config = init("thirdparty_config.json",config)
    generate_gn(config)
    generate_bundle(config)
    generate_sh(config)
    generate_toolchain(config)

if __name__ == '__main__':
    if len(sys.argv[1]) < 0:
        print("please input thirdparty path!")
    else:
        start(sys.argv[1])
